﻿using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Identity.Localization;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Settings;
using Volo.Abp.Threading;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Security.Claims;

namespace SanJ.FreeCare.Authorization.Roles
{
    /// <summary>
    /// Role manager.
    /// Used to implement domain logic for roles.
    /// </summary>
    public class RoleManager : IdentityRoleManager
    {
        protected IStringLocalizer<IdentityResource> Localizer { get; }
        protected ICancellationTokenProvider CancellationTokenProvider { get; }
        protected IPermissionManager PermissionManager { get; }

        protected IIdentityRoleRepository RoleRepository { get; }
        protected IOrganizationUnitRepository OrganizationUnitRepository { get; }
        protected ISettingProvider SettingProvider { get; }

        public RoleManager(
                IdentityRoleStore store,
                IIdentityRoleRepository roleRepository,
                IOrganizationUnitRepository organizationUnitRepository,
                IEnumerable<IRoleValidator<IdentityRole>> roleValidators,
                ILookupNormalizer keyNormalizer,
                IdentityErrorDescriber errors,
                ILogger<IdentityRoleManager> logger,
                IStringLocalizer<IdentityResource> localizer,
                ICancellationTokenProvider cancellationTokenProvider,
                ISettingProvider settingProvider,
                IPermissionManager permissionManager,
                IIdentityUserRepository userRepository,    //   7.0和8.0 有區別  
                OrganizationUnitManager organizationUnitManager,
                IDistributedCache<AbpDynamicClaimCacheItem> dynamicClaimCache
                )
                : base(
                      store,
                      roleValidators,
                      keyNormalizer,
                      errors,
                      logger,
                      localizer,
                      cancellationTokenProvider, 
                      userRepository,
                      organizationUnitRepository, 
                      organizationUnitManager, 
                      dynamicClaimCache
                      )
        {
            Localizer = localizer;
            CancellationTokenProvider = cancellationTokenProvider;
            PermissionManager = permissionManager;
            RoleRepository = roleRepository;
            SettingProvider = settingProvider;
            OrganizationUnitRepository = organizationUnitRepository;
        }

        public Task SetGrantedPermissionsAsync(IdentityRole role, IEnumerable<PermissionDefinition> permissions, bool isGrant)
        {
            //CheckPermissionsToUpdate(role, permissions);
            foreach (var item in permissions)
            {
                PermissionManager.SetForRoleAsync(role.Name, item.Name, isGrant);
            }
            return Task.CompletedTask;
        }


        public virtual async Task<List<PermissionWithGrantedProviders>> GetGrantedPermissionsAsync(IdentityRole role)
        {
            return await PermissionManager.GetAllForRoleAsync(role.Name);
        }

        public virtual async Task<IdentityRole> GetRoleByIdAsync(Guid roleId)
        {
            var role = await FindByIdAsync(roleId.ToString());
            if (role == null)
            {
                throw new ApplicationException("There is no role with id: " + roleId);
            }

            return role;
        }

        public virtual async Task AddToOrganizationUnitAsync(Guid userId, Guid ouId)
        {
            await AddToOrganizationUnitAsync(
                await RoleRepository.GetAsync(userId),
                await OrganizationUnitRepository.GetAsync(ouId)
            );
        }
        public virtual async Task AddToOrganizationUnitAsync(IdentityRole role, OrganizationUnit ou)
        {
            await OrganizationUnitRepository.EnsureCollectionLoadedAsync(ou, ou => ou.Roles, CancellationTokenProvider.Token);

            if (ou.Roles.Any(cou => cou.OrganizationUnitId == ou.Id))
            {
                return;
            }

            await CheckMaxUserOrganizationUnitMembershipCountAsync(ou.Roles.Count + 1);
            ou.AddRole(ou.Id);
            await OrganizationUnitRepository.UpdateAsync(ou, cancellationToken: CancellationToken);
        }
        private async Task CheckMaxUserOrganizationUnitMembershipCountAsync(int requestedCount)
        {
            var maxCount = IdentityRoleConsts.MaxNameLength;
            if (requestedCount > maxCount)
            {
                throw new BusinessException("一个机构的角色数量超出限制")
                    .WithData("MaxNameLength", maxCount);
            }
        }


        //private void CheckPermissionsToUpdate(IdentityRole role, IEnumerable<PermissionDefinition> permissions)
        //{
        //    if (role.Name == StaticRoleNames.Host.Admin &&
        //        (!permissions.Any(p => p.Name == HopePermissions.Pages_Administration_Roles_Edit) ||
        //         !permissions.Any(p => p.Name == HopePermissions.Pages_Administration_Users_ChangePermissions)))
        //    {
        //        throw new UserFriendlyException(L("YouCannotRemoveUserRolePermissionsFromAdminRole"));
        //    }
        //}


        private new string L(string name)
        {
            return Localizer.GetString(FreeCareConsts.LocalizationSourceName, name);
        }
    }
}
